/**
 * Project: saasoa
 * Copyright 2013  Top Digital Technology  Co. Ltd.
 * All right reserved.
 */
package com.topdt.jbpm.service.cmd;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jbpm.api.TaskService;
import org.jbpm.api.model.Transition;
import org.jbpm.pvm.internal.env.EnvironmentFactory;
import org.jbpm.pvm.internal.env.EnvironmentImpl;
import org.jbpm.pvm.internal.model.ActivityImpl;
import org.jbpm.pvm.internal.model.ProcessDefinitionImpl;
import org.jbpm.pvm.internal.model.TransitionImpl;
import org.jbpm.pvm.internal.task.TaskImpl;

import com.topdt.jbpm.identity.IdFactory;
import com.topdt.jbpm.identity.IdentityService;
import com.topdt.jbpm.identity.User;
import com.topdt.jbpm.model.Application;
import com.topdt.jbpm.model.HistTodo;
import com.topdt.jbpm.model.Todo;
import com.topdt.jbpm.model.Work;
import com.topdt.jbpm.service.Context;
import com.topdt.jbpm.service.JbpmService;

/**
 * 建立日期 : 2013-6-26 下午7:12:01<br>
 * 作者 : balance<br>
 * 模块 : <br>
 * 描述 : <br>
 * 修改历史: 序号 日期 修改人 修改原因 <br>
 * 1 <br>
 * 2 <br>
 */
public abstract class JumpWorkCmd implements Command<JumpResult> {

	protected JbpmService jbpmService;

	protected String todoId;

	protected Todo todo;

	protected Application app;

	protected Work work;

	protected TaskImpl task;

	protected TaskImpl superTask;

	protected ProcessDefinitionImpl processDefin;

	protected ActivityImpl fromActivity;

	protected ActivityImpl toActivity;

	protected List<HistTodo> histTodos;

	protected TaskService taskService;

	protected TransitionImpl transition;

	protected String outCome;

	protected HashMap<String, Object> taskVars;

	protected Map<String, Object> vars;

	protected Context context;

	protected JumpResult result;

	protected List<User> destUsers;

	public JumpResult execute(JbpmService jbpmService) {
		this.jbpmService = jbpmService;
		preExe();

		context = (Context) jbpmService.getTaskService().getVariable(
				todo.getTaskId(), Context.KEY);

		context.setCurrentActor(todo.getToUserId());

		taskVars = new HashMap<String, Object>();
		taskVars.put(Context.KEY, context);
		if (this.vars != null)
			taskVars.putAll(vars);

		EnvironmentFactory environmentfactory = (EnvironmentFactory) jbpmService
				.getProcessEngine();
		EnvironmentImpl environmentimpl = environmentfactory.openEnvironment();
		try {
			return doExecute();
		} finally {
			if (environmentimpl != null)
				environmentimpl.close();
		}

	}

	protected void preExe() {
		todo = jbpmService.getTodoDao().get(todoId);
		work = jbpmService.getWorkDao().get(todo.getWorkId());
		app = jbpmService.getAppDao().get(work.getAppId());
		this.taskService = jbpmService.getTaskService();
	}

	protected void getPreTask() {
		task = (TaskImpl) taskService.getTask(todo.getTaskId());
		superTask = task.getSuperTask();

		TaskImpl fromTask = task;

		if (superTask != null) {// 不能退回？
			fromTask = superTask;
		}
		processDefin = fromTask.getExecution().getProcessDefinition();
		fromActivity = processDefin.findActivity(fromTask.getActivityName());

		if (fromActivity != null) {
			List<ActivityImpl> acts = getPreActivity(fromActivity, 0);

			long batch = 0;
			//TODO 当前退回不支持动态分支的内部退回,会出现的现象："退回至最后提交任务分支中的上一个环节"
			for (ActivityImpl act : acts) {
				String actName = act.getName();
				List<HistTodo> todosTemp = jbpmService.getHistTodoDao().getLastTodos(work.getWorkId(), actName);
				if (todosTemp != null && todosTemp.size() > 0) {
					long batchTemp = todosTemp.get(0).getBatch();
					if (batchTemp >= batch) {
						batch = batchTemp;
						histTodos = todosTemp;
						toActivity = act;
					}
				}
			}
		}
	}

	protected void getFirstTask() {
		task = (TaskImpl) taskService.getTask(todo.getTaskId());
		TaskImpl superTask = task.getSuperTask();

		superTask = task.getSuperTask();

		TaskImpl fromTask = task;

		if (superTask != null) {// 不能退回？
			fromTask = superTask;
		}
		processDefin = fromTask.getExecution().getProcessDefinition();
		fromActivity = processDefin.findActivity(fromTask.getActivityName());
		ActivityImpl startActivity = processDefin.findActivity("start");
		Transition transition = startActivity.getOutgoingTransitions().get(0);
		toActivity = (ActivityImpl) transition.getDestination();
		histTodos = jbpmService.getHistTodoDao().getLastTodos(work.getWorkId(),
				toActivity.getName());
	}
	
	
	/** 
	 *  @Description    : 得到目标退回任务
	 *  @Method_Name    : getToTask 
	 *  @return         : void
	 *  @Creation Date  : 2015年1月5日 下午4:45:07 
	 *  @version        : v1.00
	 *  @Author         : calonlan
	 
	 *  @Update Date    : 
	 *  @Update Author  : 
	 */
	protected void getToTask() {
		task = (TaskImpl) taskService.getTask(todo.getTaskId());
		superTask = task.getSuperTask();

		TaskImpl fromTask = task;

		if (superTask != null) {// 不能退回？
			fromTask = superTask;
		}
		processDefin = fromTask.getExecution().getProcessDefinition();
		fromActivity = processDefin.findActivity(fromTask.getActivityName());
		List<Transition> transitions = (List<Transition>) fromActivity.getOutgoingTransitions();
		for (Transition tran : transitions) {
			String name = tran.getName();
			if (name != null) {
				String[] arr = name.split("_");
				if (arr.length > 1 && arr[1].equals("ht")) {
					transition = (TransitionImpl) tran;
					break;
				}
			}
		}
		toActivity = (ActivityImpl) transition.getDestination();
		histTodos = jbpmService.getHistTodoDao().getLastTodos(work.getWorkId(),
				toActivity.getName());
		//设置出口流转
		outCome = transition.getName();
	}

	protected void addOutcome() {
		if (fromActivity != null && toActivity != null) {
			transition = fromActivity.createOutgoingTransition();
			outCome = "goBack" + toActivity.getName();
			transition.setName(outCome);
			transition.setDestination(toActivity);
		}
	}

	protected void removeOutcome() {
		if (fromActivity != null && toActivity != null && transition != null) {
			List<? extends Transition> outs = fromActivity
					.getOutgoingTransitions();
			outs.remove(transition);
		}

	}

	/**
	 * 递归找可以退回的第一个节点
	 * 
	 * @param activity
	 * @param goNUM
	 * @return
	 */
	private List<ActivityImpl> getPreActivity(ActivityImpl activity, int goNUM) {

		List<ActivityImpl> activies = new ArrayList<ActivityImpl>();
		List<? extends Transition> inTransitions = activity
				.getIncomingTransitions();
		if (inTransitions == null || inTransitions.size() == 0 || goNUM < 0) {

		} else {
			for (Transition t : inTransitions) {
				ActivityImpl activ = (ActivityImpl) t.getSource();
				String type = activ.getType();
				if (goNUM == 0 && (type.equals("task") || type.equals("start"))) {// 若是task或start类型停止递归
					List<ActivityImpl> list = new ArrayList<ActivityImpl>();
					list.add(activ);
					activies = unionList(list, activies);
				} else if (type.equals("join")) {// 遇到汇聚节点 goNUM加1
					activies = unionList(getPreActivity(activ, ++goNUM),
							activies);
				} else if (type.equals("fork") || type.equals("foreach") || type.equals("decision")) {// 遇到分叉节点、循环节点goNUM减1
					activies = unionList(getPreActivity(activ, --goNUM),
							activies);
				} else
					activies = unionList(getPreActivity(activ, goNUM), activies);
			}
		}
		return activies;
	}

	private List<ActivityImpl> unionList(List<ActivityImpl> list1,
			List<ActivityImpl> list2) {
		for (ActivityImpl act1 : list1) {

			String act1Name = act1.getName();

			boolean existent = false;

			for (ActivityImpl act2 : list2) {
				String act2Name = act2.getName();
				if (act1Name.equals(act2Name)) {
					existent = true;
					break;
				}
			}

			if (!existent)
				list2.add(act1);
		}

		return list2;
	}

	protected void defaultResult() {
		creatResult();
		if (toActivity != null) {
			result.setDestActivity(toActivity.getName());
			result.setJumpAble(true);
			if (destUsers == null)
				getDestUsers();
			result.setDestUsers(destUsers);
		} else {
			result.setJumpAble(false);
		}
	}

	protected void getDestUsers() {
		if (this.histTodos != null) {
			List<User> destUsers = new ArrayList<User>();

			IdentityService idService = IdFactory.getIdentityServiceFactory()
					.getIdentityService();

			for (HistTodo todo : histTodos) {
				String userId = todo.getToUser();
				User user = idService.getUserById(userId);
				destUsers.add(user);
			}

			this.destUsers = destUsers;
		}
	}

	protected void creatResult() {
		if (result == null)
			result = new JumpResult();
	}

	protected boolean isFirstActivity(ActivityImpl activity) {
		List<? extends Transition> inTransitions = activity
				.getIncomingTransitions();
		if (inTransitions == null || inTransitions.size() == 0) {
			return false;
		} else {
			Transition t = inTransitions.get(0);
			String type = t.getSource().getType();
			return type.equals("start");
		}
	}

	protected abstract JumpResult doExecute();

}
